#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012 Mike Sheldon <elleo@gnu.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


from PySide import QtCore, QtGui, QtDeclarative
import xml.etree.cElementTree as etree
import sys, os, os.path, signal, shutil
import subprocess, zipfile


class Tizmee:


	def __init__(self):
		self.app = QtGui.QApplication(sys.argv)
		self.app.setApplicationName("Tizmee")
		signal.signal(signal.SIGINT, signal.SIG_DFL)

		self.cacheDir = QtGui.QDesktopServices.storageLocation(QtGui.QDesktopServices.CacheLocation)
		if not os.path.exists(self.cacheDir):
			os.mkdir(self.cacheDir)
		if os.path.exists("/home/user/MyDocs/"):
			# Maemo/Harmattan
			self.appDir = "/home/user/MyDocs/TizenApps"
		else:
			self.appDir = os.path.join(os.path.expanduser("~"), 'TizenApps')
		if not os.path.exists(self.appDir):
			os.mkdir(self.appDir)

		self.appsModel = AppsModel()

		self.view = QtDeclarative.QDeclarativeView()
		self.view.setSource("/opt/tizmee/qml/Tizmee.qml")
		self.rootObject = self.view.rootObject()
		self.context = self.view.rootContext()
		self.context.setContextProperty('appsModel', self.appsModel)
		self.rootObject.openFile("Launcher.qml")
		self.rootObject.quit.connect(sys.exit)
		self.rootObject.launch.connect(self.launch)
		self.view.showFullScreen()

		self.populate_apps()

		sys.exit(self.app.exec_())


	def populate_apps(self):
		for filename in os.listdir(self.appDir):
			wgtPath = os.path.join(self.appDir, filename)
			if zipfile.is_zipfile(wgtPath):
				appPath = os.path.join(self.cacheDir, filename)
				if not os.path.exists(appPath):
					os.mkdir(appPath)
				zapp = zipfile.ZipFile(wgtPath)
				config = zapp.open("config.xml")
				tree = etree.parse(config)
				root = tree.getroot()
				name = root.findtext("{http://www.w3.org/ns/widgets}name")
				icon = root.find("{http://www.w3.org/ns/widgets}icon").get("src")
				if icon:
					iconPath = os.path.join(appPath, icon)
					zapp.extract(icon, appPath)
					icon = iconPath
				try:
					startfile = root.find("{http://www.w3.org/ns/widgets}content").get("src")
				except:
					startfile = "index.html"
				app = App(name, wgtPath, appPath, startfile, icon)
				self.appsModel.add(app)
		if self.appsModel.rowCount() == 0:
			self.rootObject.showExitMessage("No Tizen apps installed", "You don't currently have any Tizen apps installed. To install an app place its .wgt file in %s." % self.appDir)


	def launch(self, wgtPath, path, startfile):
		zapp = zipfile.ZipFile(wgtPath)
		zapp.extractall(path)
		tjspath = os.path.join(path, "tizenjs")
		if os.path.exists(tjspath):
			shutil.rmtree(tjspath)
		shutil.copytree("/opt/tizmee/www/js/", tjspath)
		# HACK: Inject our JavaScript for implementing the Tizen API
		# TODO: Find a way to automatically do this on file load
		for filename in os.listdir(path):
			if filename[-4:].lower() == 'html' or filename[-3:].lower() == 'htm':
				htmlfile = open(os.path.join(path, filename), 'r')
				html = htmlfile.read()
				htmlfile.close()
				htmlfile = open(os.path.join(path, filename), 'w')
				html = html.replace("<head>", """<head>
					<script language='javascript' type='text/javascript' src='tizenjs/cordova.js'></script>
					<script language='javascript' type='text/javascript' src='tizenjs/cordova.qt.js'></script>
					<script language='javascript' type='text/javascript' src='tizenjs/tizensysteminfo.js'></script>
				""")	
				if 'data-framework-viewport-scale="true"' not in html and "data-framework-viewport-scale='true'" not in html:
					# Handle scaling if the Tizen libs aren't doing it for us
					html = html.replace("<head>", """<head>
						<meta name="viewport" content="width=720; height=1280; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
						<style>
							body {
								zoom: 0.74;
							}
						</style>
					""")
				htmlfile.write(html)
				htmlfile.close()

		subprocess.Popen(["/usr/bin/invoker", "-S", "/opt/tizmee/tizmee-splash.png", "--type=e", "/opt/tizmee/bin/cordovaqt", path, startfile])



class App(QtCore.QObject):


	def __init__(self, name, wgtPath, path, startfile, icon):
		self.name = name
		self.wgtPath = wgtPath
		self.path = path
		self.startfile = startfile
		self.icon = icon



class AppsModel(QtCore.QAbstractListModel):


	NAME_ROLE = QtCore.Qt.UserRole + 1
	WGTPATH_ROLE = QtCore.Qt.UserRole + 2
	PATH_ROLE = QtCore.Qt.UserRole + 3
	STARTFILE_ROLE = QtCore.Qt.UserRole + 4
	ICON_ROLE = QtCore.Qt.UserRole + 5


	def __init__(self, parent=None):
		super(AppsModel, self).__init__(parent)
		self._data = []
		keys = {}
		keys[AppsModel.NAME_ROLE] = 'name'
		keys[AppsModel.WGTPATH_ROLE] = 'wgtpath'
		keys[AppsModel.PATH_ROLE] = 'path'
		keys[AppsModel.STARTFILE_ROLE] = 'startfile'
		keys[AppsModel.ICON_ROLE] = 'icon'
		self.setRoleNames(keys)


	def rowCount(self, index=0):
		return len(self._data)


	def data(self, index, role):
		app = self._data[index.row()]

		if role == AppsModel.NAME_ROLE:
			return app.name
		elif role == AppsModel.WGTPATH_ROLE:
			return app.wgtPath
		elif role == AppsModel.PATH_ROLE:
			return app.path
		elif role == AppsModel.STARTFILE_ROLE:
			return app.startfile
		elif role == AppsModel.ICON_ROLE:
			return app.icon
		else:
			return None


	def add(self, app):
		self.beginInsertRows(QtCore.QModelIndex(), 0, 0) #notify view about upcoming change        
		self._data.insert(0, app)
		self.endInsertRows() #notify view that change happened


	def addToEnd(self, app):
		count = len(self._data)
		self.beginInsertRows(QtCore.QModelIndex(), count, count)
		self._data.insert(count, app)
		self.endInsertRows()


if __name__ == "__main__":
	Tizmee()
